<?php


namespace app\common\model;


use think\cache\driver\Redis;
use think\facade\Cache;
use think\facade\Cookie;
use think\Model;
use app\common\model\Admin as adminModel;
use app\common\model\AdminRoleRel as adminRoleRelModel;

class Operation extends Model {

    protected $pk = 'id';

    const MENU_START = 1;       //起始节点
    const MENU_MANAGE = 2;      //管理平台起始菜单id
    const PERM_TYPE_SUB = 1;    //主体权限
    const PERM_TYPE_HALFSUB = 2;
    const PERM_TYPE_REL  = 3;   //附加权限


    public function parentInfo()
    {
        return $this->hasOne('Operation','id', 'parent_id')->bind([
            'parent_name' => 'name'
        ]);
    }
    public function parentMenuInfo()
    {
        return $this->hasOne('Operation','id', 'parent_menu_id')->bind([
            'parent_menu_name' => 'name'
        ]);
    }


//    public function manageMenu($admin_id,$type = self::PERM_TYPE_SUB){
//
//        $parent_menu_id = self::MENU_MANAGE;
//
//        if(cache('?manage_operation_'.$admin_id)&& $type == self::PERM_TYPE_SUB){
//            $menuTree = cache('manage_operation_'.$admin_id);
//        }else{
//            $list = $this->manageOperation($admin_id,$type);
//
//            $menuTree = $this->createTree($list,$parent_menu_id);        //构建菜单树
//
//            //存储
//            if($type == self::PERM_TYPE_SUB){
//                cache('manage_operation_'.$admin_id,$menuTree,3600);    //当为1时最常用
//            }
//        }
//
//        $list = $this->manageOperation($admin_id,$type);
//
//        $menuTree = $this->createTree($list,$parent_menu_id);        //构建菜单树
//
//        //存储
//        if($type == self::PERM_TYPE_SUB){
//            cache('manage_operation_'.$admin_id,$menuTree,3600);    //当为1时最常用
//        }
//
//        return  $menuTree;
//
//    }


    //常规方法
    public function manageMenu($admin_id,$type = self::PERM_TYPE_SUB){


        $parent_menu_id = self::MENU_MANAGE;
        if(Cache::has('manage_operation_list_'.$admin_id) && $type == self::PERM_TYPE_SUB){
            $list = Cache::get('manage_operation_list_'.$admin_id);
            $menuTree = $this->createTree($list,$parent_menu_id);        //构建菜单树
        }else{
            $list = $this->manageOperation($admin_id,$type);
            $menuTree = $this->createTree($list,$parent_menu_id);        //构建菜单树
            if($type == self::PERM_TYPE_SUB){
                Cache::set('manage_operation_list_'.$admin_id,$list,3600);    //当为1时最常用
            }
        }
        return  $menuTree;
    }


    //取管理员所对应的所有角色的所有节点信息
    public function manageOperation($admin_id,$type = self::PERM_TYPE_HALFSUB){
        $adminModel = new adminModel();
        //如果是超级管理员，直接返回所有
        if($admin_id == $adminModel::SUPER_ID){
            //直接取所有数据，然后返回
            $list = $this->where('perm_type','<=',$type)->order('sort desc')->select();
        }else{
            $adminRoleRelModel = new adminRoleRelModel();
            //取此管理员的所有角色
            $roles = $adminRoleRelModel->where('admin_id',$admin_id)->select();
            if(!$roles->isEmpty()){
                $roles = $roles->toArray();
                $roles = array_column($roles,'role_id');
            }else{
                $roles = [];
            }
            //到这里就说明用户是店铺的普通管理员，那么就取所有的角色所对应的权限
            $list = $this
                ->distinct(true)
                ->field('o.*')
                ->alias('o')
                ->join('admin_role_operation_rel aror', 'o.id = aror.operation_id')
                ->where('aror.admin_role_id','IN',$roles)
                ->where('o.perm_type','<=',$type)
                ->order('o.sort desc')
                ->select();
        }
        if($list->isEmpty()){
            $list = [];     //啥权限都没有
        }else{
            $list = $list->toArray();
        }
        return $list;
    }


    public function createTree($list,$parent_menu_id)
    {
        $data = [];
        foreach($list as $k => $v){
            if($v['parent_menu_id'] == $parent_menu_id){
                $row = $v;
                //取当前节点的url
                $row['url'] = $this->getUrl($v['id']);

                $row['children'] = $this->createTree($list,$v['id']);

                $data[] = $row;
            }
        }

        return $data;
    }



    private function getUrl($operation_id){
        static $list = [];
        if(!$list){
            $all = $this->select();
            if(!$all->isEmpty()){
                $all = $all->toArray();
            }else{
                $all = [];
            }
            foreach($all as $v){
                $list[$v['id']] = $v;
            }
        }

        if(!isset($list[$operation_id])){
            return "";
        }
        if($list[$operation_id]['type'] == 'm'){
            return url($list[$operation_id]['code'] . '/index/index');          //一个模型，搞什么url？
        }
        if($list[$operation_id]['type'] == 'c'){
            if(isset($list[$list[$operation_id]['parent_id']])){
                return url($list[$list[$operation_id]['parent_id']]['code'] . '/'.$list[$operation_id]['code'].'/index');
            }else{
                return "";
            }
        }
        if($list[$operation_id]['type'] == 'a'){
            //取控制器
            if(isset($list[$list[$operation_id]['parent_id']]) && isset($list[$list[$list[$operation_id]['parent_id']]['parent_id']])){
                return url($list[$list[$list[$operation_id]['parent_id']]['parent_id']]['code'] . '/'.$list[$list[$operation_id]['parent_id']]['code'].'/'.$list[$operation_id]['code']);
            }else{
                return "";
            }
        }
        return "";

    }


    public function tableData($post)
    {
        if(isset($post['limit'])){
            $limit = $post['limit'];
        }else{
            $limit = config('paginate.list_rows');
        }
        $tableWhere = $this->tableWhere($post);
        $list = $this->with(['parentInfo','parentMenuInfo'])->field($tableWhere['field'])->where($tableWhere['where'])->order($tableWhere['order'])->paginate($limit);
        $data = $this->tableFormat($list->getCollection());         //返回的数据格式化，并渲染成table所需要的最终的显示数据类型

        $re['code'] = 0;
        $re['msg'] = '';
        $re['count'] = $list->total();
        $re['data'] = $data;
        //取所有的父节点，构建路径
        if(isset($post['parent_id'])){
            $re['parents'] = $this->getParents($post['parent_id']);
        }else{
            $re['parents'] = [];
        }

        return $re;
    }

    //递归取得所有的父节点
    public function getParents($operation_id){
        $data = [];
        $info = $this->where(['id' => $operation_id])->find();
        if(!$info){
            return $data;
        }
        //判断是否还有父节点，如果有，就取父节点，如果没有，就返回了
        if($info['parent_id'] !=self::MENU_START){
            $data = $this->getParents($info['parent_id']);      //返回空数组或者二维数组
        }
        array_push($data,$info->toArray());
        return $data;
    }


    protected function tableWhere($post)
    {
        $where = [];
        if(isset($post['parent_id']) && $post['parent_id'] != ""){
            $where[] = ['parent_id', '=', $post['parent_id']];
        }


        $result['where'] = $where;
        $result['field'] = "*";
        $result['order'] = ['sort'=>'ASC','id'=>'DESC'];
        return $result;
    }


    protected function tableFormat($list)
    {
        foreach($list as $k => $v){
            if(isset($v['type'])){
                $list[$k]['type'] = config('params.operation.type')[$v['type']];
            }
            if(isset($v['perm_type']) && isset($v['parent_menu_id'])){
                if($v['parent_menu_id'] != '0'){
                    $list[$k]['perm_type'] = config('params.operation.perm_type')[$v['perm_type']];
                }else{
                    $list[$k]['perm_type'] = "";
                }
            }

        }
        return $list;
    }


    public function toAdd($data){
        $status = [
            'status' => false,
            'data' => '',
            'msg' => ''
        ];
        if(!isset($data['id']) || !isset($data['parent_id']) || !isset($data['name']) || !isset($data['code']) || !isset($data['type']) || !isset($data['perm_type'])){
            return error_code(11092);
        }
        //如果是方法，code换成小写
        if($data['type'] == 'a'){
            $data['code'] = strtolower($data['code']);
        }

        //校验父节点和当前类型
        if($data['parent_id'] != self::MENU_START){
            //判断是否是合法的父节点,既然是父节点，肯定不可能是方法，因为方法不可能成为父节点
            $parentInfo = $this->where('type','<>','a')->where('id','=',$data['parent_id'])->find();
            if(!$parentInfo){
                return error_code(10000);
            }
            //有父节点了，那么就得判断当前的类型和父类型是否对应上
            if($parentInfo['type'] == 'm'){
                if($data['type'] != 'c'){
                    return error_code(11093);
                }
            }
            if($parentInfo['type'] == 'c'){
                if($data['type'] != 'a'){
                    return error_code(11094);
                }
            }

        }else{
            if($data['type'] != 'm'){
                return error_code(11095);
            }
        }
        //判断当前编码是否重复
        $where[] = ['parent_id','=',$data['parent_id']];
        $where[] = ['code','=',$data['code']];
        if($data['id'] != ""){
            $where[] = ['id','<>',$data['id']];
        }
        $info = $this->where($where)->find();
        if($info){
            return error_code(11096);
        }

        //判断父菜单节点是否存在
        if($data['parent_menu_id'] != self::MENU_START){
            $menuParentInfo = $this->where('id','=',$data['parent_menu_id'])->find();
            if(!$menuParentInfo){
                return error_code(10000);
            }
            //如果是控制器，父菜单节点必须和父节点保持一致，
            //此判断outl了
//            if($data['type'] == 'c' && ($data['parent_id'] != $data['parent_menu_id'])){
//                return error_code(11099);
//            }
        }

        if($data['id'] != ""&&$data['id']>0){
            //当前是修改，就需要判断是否会陷入死循环
            if(!$this->checkDie($data['id'],$data['parent_id'],'parent_id')){
                return error_code(11097);
            }
            if(!$this->checkDie($data['id'],$data['parent_menu_id'],'parent_menu_id')){
                return error_code(11098);
            }
            $id = $data['id'];
            unset($data['id']);
            $re = $this->where('id',$id)->save($data);
        }else{
            $re = $this->insert($data);
        }


        if($re){
            $status['status'] = true;
        }
        return $status;

    }


    private function checkDie($id,$p_id,$p_str,$n=10)
    {
        //设置计数器，防止极端情况下陷入死循环了（其他地方如果设置的有问题死循环的话，这里就报错了）
        if($n <= 0){
            return false;
        }
        if($id == $p_id){
            return false;
        }
        if($id == self::MENU_START || $p_id == self::MENU_START){
            return true;
        }
        $pinfo = $this->where(['id'=>$p_id])->find();
        if(!$pinfo){
            return false;
        }
        if($pinfo[$p_str] == self::MENU_START){
            return true;
        }
        if($pinfo[$p_str] == $id){
            return false;
        }
        return $this->checkDie($id,$pinfo[$p_str],$p_str,--$n);
    }


    public function toDel($id)
    {
        $status = [
            'status' => false,
            'data' => '',
            'msg' => ''
        ];
        //如果没有下级了，就可以删了
        $children = $this->where(['parent_id'=>$id])->select();
        if($children->isEmpty()){
            $re = $this->where(['id'=>$id])->delete();
            if($re){
                $status['status'] = true;
            }else{
                return  error_code(10023);
            }
            return $status;
        }else{
            return error_code(11091);
        }
    }


    /**
     * 根据传过来的字段构建设置角色的权限树，结构主要是适配Dtree的数据结构
     * @param $manageMenu       当前登陆者的权限树，
     * @param $nodeList         当前角色的on的权限
     * @param int $level        层级
     * @param int $parentId     父id
     * @return array
     */
    public function setRoleManageMenu($manageMenu,$nodeList,$level=1,$parentId=0){
        $dtreeData = [];
        foreach($manageMenu as $v){
            $v['title'] = $v['name'];

            $v['level'] = $level;
            $v['parentId'] = $parentId;
            if(in_array($v['id'],$nodeList)){
                $isChecked = '1';
            }else{
                $isChecked = '0';
            }
            if(isset($v['children']) && $v['children']){
                $isLast = false;
                $children = $this->setRoleManageMenu($v['children'],$nodeList,$level+1,$v['id']);
            }else{
                $isLast = true;
                $children = [];
            }
            $dtreeData[] = [
                'id' => $v['id'],
                'title' => $v['name'],
                'isLast' => $isLast,
                'level' => $level,
                'parentId' => $parentId,
                'checkArr' => [
                    'type' => '0',
                    'isChecked' => $isChecked
                ],
                'children' => $children
            ];
        }
        return $dtreeData;
    }


    /**
     * 判断控制器和方法是否不需要校验
     * @param $p_id
     * @param $cont_name
     * @param $act_name
     * @return bool
     */
    public function checkNeedPerm($p_id,$cont_name,$act_name)
    {
        if(isset($this->noPerm[$p_id][$cont_name])){
            if(in_array($act_name,$this->noPerm[$p_id][$cont_name])){
                return true;
            }
        }
        return false;
    }
}